home *** CD-ROM | disk | FTP | other *** search
- /*===================================================================
- *
- * FILE:
- * prs2plans.c
- *
- * IDENTIFICATION:
- * $Header: /private/postgres/src/rules/prs2/RCS/prs2plans.c,v 1.28 1992/07/13 06:10:28 mao Exp $
- *
- * DESCRIPTION:
- * Various useful routines called by the PRS2 code...
- *
- *
- *===================================================================
- */
-
- #include "tmp/postgres.h"
- #include "tmp/datum.h"
- #include "catalog/syscache.h"
- #include "utils/log.h"
- #include "nodes/plannodes.h" /* for EState */
- #include "nodes/plannodes.a.h" /* for EState */
- #include "nodes/execnodes.h" /* for EState */
- #include "nodes/execnodes.a.h" /* for EState */
- #include "executor/execdefs.h"
- #include "executor/x_execmain.h"
- #include "parser/parsetree.h"
- #include "utils/fmgr.h"
- #include "tcop/dest.h"
-
- #include "catalog/pg_prs2rule.h"
- #include "catalog/pg_prs2plans.h"
-
- extern EState CreateExecutorState();
- RuleLock prs2SLOWGetLocksFromRelation();
-
- /*-------------------------------------------------------------------
- * prs2GetRulePlanFromCatalog
- * Given a rule id and a plan number get the appropriate plan
- * from the system catalogs. At the same time construct a list
- * with all the Param nodes contained in this plan.
- */
- LispValue
- prs2GetRulePlanFromCatalog(ruleId, planNumber, paramListP)
- ObjectId ruleId;
- Prs2PlanNumber planNumber;
- ParamListInfo *paramListP;
- {
-
-
- HeapTuple planTuple;
- struct prs2plans *planStruct;
- char *planString;
- LispValue plan;
- char *getstruct();
- char *t;
-
- /*
- * get the tuple form the system cache
- */
- planTuple = SearchSysCacheTuple(PRS2PLANCODE, ruleId, planNumber);
- if (planTuple == NULL) {
- /*
- * No such rule exist! Complain!
- */
- elog(WARN,
- "prs2GetRulePlanFromCatalog: plan NOT found (rulid=%ld,planno=%d)\n",
- ruleId, planNumber);
- return(LispNil);
- }
-
- /*
- * given the tuple extract the 'struct prs2plans' structure
- */
- planStruct = (struct prs2plans *) GETSTRUCT(planTuple);
-
- /*
- * This is a little bit tricky but it works!
- *
- * t = VARDATA(&planStruct->prs2code);
- * planString = PSIZESKIP(t);
- *
- * Unfortunately it assumes the wrong semantics, and this
- * causes problems when things change.
- */
- planString = VARDATA(&(planStruct->prs2code));
-
- if (paramListP == NULL)
- plan = StringToPlan(planString);
- else
- plan = StringToPlanWithParams(planString, paramListP);
-
- return(plan);
- }
-
- /*------------------------------------------------------------------
- *
- * prs2GetLocksFromRelation
- *
- * Given a relation, find all its relation level locks.
- * We have to go to the RelationRelation, get the tuple that corresponds
- * to the given relation and extract its locks field.
- *
- * NOTE: we are returning a pointer to a *copy* of the locks!
- */
- RuleLock
- prs2GetLocksFromRelation(relationName)
- Name relationName;
- {
- HeapTuple relationTuple;
- RuleLock relationLocks;
-
- /*
- * Search the system cache for the relation tuple
- */
- relationTuple = SearchSysCacheTuple(RELNAME,
- relationName,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL);
- if (!HeapTupleIsValid(relationTuple)) {
- elog(WARN, "prs2GetLocksFromRelation: no rel with name '%s'\n",
- relationName);
- }
-
- relationLocks = prs2GetLocksFromTuple(relationTuple, InvalidBuffer);
-
- return(relationLocks);
- }
-
- /*------------------------------------------------------------------
- * prs2SLOWGetLocksFromRelation
- *
- * get the locks but without using the sys cache.
- * Do a scan in the pg_class...
- * The only reason for the existence of this routine was a flaky system
- * cache... I kust keep it here in case things are broken again.
- *
- *------------------------------------------------------------------
- */
- RuleLock
- prs2SLOWGetLocksFromRelation(relationName)
- Name relationName;
- {
- Relation rel;
- TupleDescriptor tdesc;
- ScanKeyData scanKey;
- HeapScanDesc scanDesc;
- HeapTuple tuple;
- Buffer buffer;
- RuleLock locks;
-
- rel = RelationNameOpenHeapRelation(Name_pg_relation);
- tdesc = RelationGetTupleDescriptor(rel);
- /*----
- * Scan pg_relation
- */
- ScanKeyEntryInitialize(&scanKey.data[0], 0, Anum_pg_relation_relname,
- F_CHAR16EQ, NameGetDatum(relationName));
- scanDesc = RelationBeginHeapScan(rel, false, NowTimeQual, 1, &scanKey);
- tuple = HeapScanGetNextTuple(scanDesc, false, &buffer);
- locks = prs2GetLocksFromTuple(tuple, buffer);
- RelationCloseHeapRelation(rel);
- HeapScanEnd(scanDesc);
-
- return(locks);
- }
- /*------------------------------------------------------------------
- *
- * prs2CheckQual
- *
- * Return 1 if the given rule qualification is true
- * (i.e. it returns at least one tuple).
- * Otherwise return 0.
- *
- * NOTE: A null qualification always evaluates to true.
- *
- */
- int
- prs2CheckQual(planQual, paramList, prs2EStateInfo)
- LispValue planQual;
- ParamListInfo paramList;
- Prs2EStateInfo prs2EStateInfo;
- {
- int status;
-
- if (planQual == LispNil)
- return(1);
-
- status = prs2RunOnePlanAndGetValue(
- planQual,
- paramList,
- prs2EStateInfo,
- NULL, NULL, NULL);
-
- return(status);
- }
-
- /*------------------------------------------------------------------
- *
- * prs2RunActionPlans
- *
- */
-
- void
- prs2RunActionPlans(plans, paramList, prs2EStateInfo)
- LispValue plans;
- ParamListInfo paramList;
- Prs2EStateInfo prs2EStateInfo;
- {
- int feature;
- LispValue onePlan;
-
- foreach(onePlan, plans) {
- /*
- * XXX SOS XXX
- * What kind of 'feature' should we use ??
- */
- feature = EXEC_RUN;
- prs2RunOnePlan(CAR(onePlan), paramList, prs2EStateInfo, feature);
- }
-
- }
-
- /*------------------------------------------------------------------
- *
- * prs2RunOnePlanAndGetValue
- *
- * Run a retrieve plan and return 1 if a tuple was found or 0 if there
- * was no tuple.
- *
- * Sometimes when we call this routine, we are only interested in
- * whether there is a tuple returned or not, but we are *not*
- * interested in the tuple itself (for instance, when we test
- * a rule qualification).
- * In this case, "valueP" and "isNullP" are NULL
- *
- * On the other hand, sometimes (when we execute the action part of an
- * "on retrieve ... do instead retrieve ..." rule) we want the value of
- * the tuple's attribute too. This tuple has always one attribute.
- * NOTE: We make a copy of the attribute!
- *
- */
-
- int
- prs2RunOnePlanAndGetValue(actionPlan, paramList, prs2EStateInfo,
- valueP, isNullP)
- LispValue actionPlan;
- ParamListInfo paramList;
- Prs2EStateInfo prs2EStateInfo;
- Datum *valueP;
- Boolean *isNullP;
- {
-
- AttributeNumber numberOfAttributes;
- TupleDescriptor resultTupleDescriptor;
- LispValue queryDescriptor;
- LispValue res1, res2, res3;
- EState executorState;
- HeapTuple resultTuple;
- TupleTableSlot slot;
- bool oldPolicy;
- int status;
-
- queryDescriptor = prs2MakeQueryDescriptorFromPlan(actionPlan);
-
- executorState = CreateExecutorState();
- set_es_param_list_info(executorState, paramList);
- set_es_prs2_info(executorState, prs2EStateInfo);
-
- res1 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(EXEC_START), LispNil));
-
-
- /*
- * When the executor is called with EXEC_START it returns
- * "lispCons(LispInteger(n), lispCons(t, lispNil))"
- * where 'n' is the number of attributes in the result tuple
- * and 't' is an 'AttributePtr'.
- * XXX Note: it appears that 'AttributePtr' and 'TupleDescriptor'
- * are the same thing!
- */
-
- /*
- * XXX -
- * Unfortunately, by now the executor has freed (with pfree) the tuple
- * descriptor!!! You will have to either copy it or work out something
- * with Cim - I hacked the executor to avoid freeing this for now,
- * but it *should* be freeing these things to prevent memory leaks.
- *
- * -- Greg
- */
- numberOfAttributes = (AttributeNumber) CInteger(CAR(res1));
- resultTupleDescriptor = (TupleDescriptor) CADR(res1);
-
-
- /*
- * now retrieve one tuple
- */
- res2 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(EXEC_RETONE), LispNil));
- /*
- * "res2" is a 'TupleTableSlot', containing a tuple that will
- * might be freed by the next call to the executor (with operation
- * EXEC_END). However, we might want to use the values of this
- * tuple, in which case we must not free it.
- * To do that, we copy the given slot to another one
- * and change the "freeing policy" of the original slot
- * to "false"
- */
- slot = (TupleTableSlot) res2;
- resultTuple = (HeapTuple) ExecFetchTuple(slot);
- if (resultTuple == NULL) {
- /*
- * No tuple was returned...
- * XXX What shall we do??
- * Options:
- * 1) bomb!
- * 2) continue with the next rule
- * 3) assume a nil value
- * Currently option (2) is implemented.
- */
- status = 0; /* this means no value found */
- } else {
- /*
- * A tuple was found. Find the value of its attribute.
- * NOTE: for the time being we assume that this tuple
- * has only one attribute!
- */
- Datum val;
-
- if (valueP != NULL && isNullP != NULL) {
- val = HeapTupleGetAttributeValue(
- resultTuple,
- InvalidBuffer,
- (AttributeNumber) 1,
- resultTupleDescriptor,
- isNullP);
- *valueP = datumCopy(val,
- resultTupleDescriptor->data[0]->atttypid,
- resultTupleDescriptor->data[0]->attbyval,
- (Size) resultTupleDescriptor->data[0]->attlen);
-
- }
- status = 1;
- }
-
- /*
- * let the executor do the cleaning up...
- */
- res3 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(EXEC_END), LispNil));
-
- return(status);
- }
-
- /*------------------------------------------------------------------
- *
- * prs2RunOnePlan
- *
- * Run one plan. Ignore the return values from the executor.
- *
- */
-
- void
- prs2RunOnePlan(actionPlan, paramList, prs2EStateInfo, operation)
- LispValue actionPlan;
- ParamListInfo paramList;
- Prs2EStateInfo prs2EStateInfo;
- int operation;
- {
- LispValue queryDescriptor;
- LispValue res1, res2, res3;
- EState executorState;
- TupleDescriptor foo; /* XXX Hack for making copy of tuple descriptor */
-
- queryDescriptor = prs2MakeQueryDescriptorFromPlan(actionPlan);
-
- executorState = CreateExecutorState();
- set_es_param_list_info(executorState, paramList);
- set_es_prs2_info(executorState, prs2EStateInfo);
-
- res1 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(EXEC_START), LispNil));
-
- res2 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(operation), LispNil));
- res3 = ExecMain(queryDescriptor, executorState,
- lispCons(lispInteger(EXEC_END), LispNil));
- }
-
- /*------------------------------------------------------------------
- *
- * prs2IsRuleInsteadFromRuleInfo
- *
- * Given the 'rule info' stored in pg_prs2plans return true iff
- * a rule is an 'instead' rule, otherwise return false
- */
- Boolean
- prs2IsRuleInsteadFromRuleInfo(ruleInfo)
- LispValue ruleInfo;
- {
- LispValue t;
- char *s;
-
- t = CAR(ruleInfo);
- s = CString(t);
-
- if (!strcmp("instead", s)) {
- return((Boolean) 1);
- } else {
- return((Boolean) 0);
- }
- }
-
- /*------------------------------------------------------------------
- *
- * prs2GetEventAttributeNumberFromRuleInfo
- *
- * Given the 'rule info' as stored in pg_prs2plans,
- * return the attribute number of the attribute specified in the
- * 'ON EVENT to REL.attr' clause
- */
- AttributeNumber
- prs2GetEventAttributeNumberFromRuleInfo(ruleInfo)
- LispValue ruleInfo;
- {
- LispValue t;
- int n;
-
- t = CAR(CDR(ruleInfo));
- n = CInteger(t);
-
- return(n);
- }
-
-
- /*------------------------------------------------------------------
- *
- * prs2GetUpdatedAttributeNumberFromRuleInfo
- *
- * Given the 'rule info' as stored in pg_prs2plans,
- * return the attribute number of the attribute of the CURRENT tuple
- * which is updated by the rule. This only applies to rules of the
- * form 'ON RETRIEVE TO REL.X DO RETRIEVE INSTEAD (X = ...)' or
- * 'ON REPLACE TO REL.Y DO REPLACE CURRENT(X = ....)'.
- */
- AttributeNumber
- prs2GetUpdatedAttributeNumberFromRuleInfo(ruleInfo)
- LispValue ruleInfo;
- {
- LispValue t;
- int n;
-
- t = CAR(CDR(CDR(ruleInfo)));
- n = CInteger(t);
-
- return(n);
- }
-
-
- /*------------------------------------------------------------------
- *
- * prs2MakeQueryDescriptorFromPlan
- *
- * Given the actionPlan, the paramList and the prs2EStateInfo,
- * create a query descriptor
- */
-
- LispValue
- prs2MakeQueryDescriptorFromPlan(actionPlan)
- LispValue actionPlan;
- {
- LispValue queryDescriptor;
- LispValue parseTree;
- LispValue plan;
- LispValue command;
-
-
- /*
- * the actionPlan must be a list containing the parsetree & the
- * plan that has to be executed.
- */
- parseTree = prs2GetParseTreeFromOneActionPlan(actionPlan);
- plan = prs2GetPlanFromOneActionPlan(actionPlan);
-
- command = root_command_type_atom(parse_root(parseTree));
-
- queryDescriptor = (LispValue)
- MakeQueryDesc(
- command,
- parseTree,
- plan,
- LispNil,
- LispNil,
- LispNil,
- LispNil,
- lispInteger(0),
- None);
-
- return(queryDescriptor);
- }
-